/********************************************
 * 功能说明: Authority实体与DTO之间接口数据转换实现
 * 模块名称:
 * 系统名称:
 * 软件版权: Frank
 * 系统版本: 1.0.0.1
 * 开发人员:
 * 开发时间: 2019-12-18 18:41:08
 * 审核人员:
 * 相关文档:
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.spring.arch.uaa.web.converter;

import com.spring.arch.common.converter.AbstractConverter;
import com.spring.arch.uaa.dto.AuthorityDTO;
import com.spring.arch.uaa.errorcode.UaaErrorCode;
import com.spring.arch.common.converter.AbstractConverter;
import com.spring.arch.common.exception.ExceptionHolder;
import com.spring.arch.uaa.dto.AuthorityDTO;
import com.spring.arch.uaa.model.Authority;
import com.spring.arch.uaa.repository.AuthorityRepository;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.spring.arch.uaa.errorcode.UaaErrorCode.E2001005002;
import static com.spring.arch.uaa.errorcode.UaaErrorCode.E2001006002;

/**
 * Authority实体与DTO之间接口数据转换实现
 *
 * @author Frank
 * @version 1.0.0.1
 * @since 2019-12-18 18:41:08
 */
@Component
public class AuthorityConverter extends AbstractConverter<Authority, AuthorityDTO> {

    @Autowired
    private AuthorityRepository authorityRepository;

    @Override
    public Authority toModel(@NonNull final AuthorityDTO dto) {
        if(dto.isNew()) {
            return constructModel(dto);
        } else {
            return updateModel(dto);
        }
    }

    @Override
    public AuthorityDTO toDTO(@NonNull final Authority model) {
        final AuthorityDTO dto = new AuthorityDTO();

        dto.setParentId(model.getParent() != null ? model.getParent().getId() : null);
        dto.setCode(model.getCode());
        dto.setName(model.getName());
        dto.setCname(model.getCname());
        dto.setType(model.getType());
        dto.setPath(model.getUrl());
        dto.setIcon(model.getIcon());
        dto.setSequence(model.getSequence());
        dto.setControlRange(model.getControlRange());
        dto.setModuleType(model.getModuleType());
        dto.setHideInMenu(model.getHideInMenu());
        dto.setHttpMethod(model.getHttpMethod());
        dto.setComponent(model.getComponent());

        this.convertCommonToDTO(model, dto);

        return dto;
    }

    /**
     * 构建新Model
     */
    private Authority constructModel(final AuthorityDTO dto) {
        final Authority model = new Authority();
        model.setCode(dto.getCode());
        model.setType(dto.getType());
        this.dtoToModel(dto, model);
        return model;
    }

    /**
     * 更新Model
     */
    private Authority updateModel(final AuthorityDTO dto) {
        final Authority model = this.authorityRepository.findById(dto.getId())
                .orElseThrow(() -> ExceptionHolder.serviceException(UaaErrorCode.E2001005002, Authority.class.getSimpleName()));
        this.dtoToModel(dto, model);
        return model;
    }

    private void dtoToModel(final AuthorityDTO dto, final Authority model) {
        UUID parentId = dto.getParentId();
        if (parentId != null) {
            Authority parent = authorityRepository.findById(parentId)
                    .orElseThrow(() -> ExceptionHolder.serviceException(UaaErrorCode.E2001006002, String.valueOf(parentId)));
            model.setParent(parent);
        }

        model.setName(dto.getName());
        model.setControlRange(dto.getControlRange());
        model.setModuleType(dto.getModuleType());
        model.setUrl(dto.getPath());
        model.setHttpMethod(dto.getHttpMethod());
        model.setIcon(dto.getIcon());
        model.setSequence(dto.getSequence());

    }

    public List<AuthorityDTO> toTree(Collection<Authority> authorities) {
        List<AuthorityDTO> res = new ArrayList<>();
        if (!CollectionUtils.isEmpty(authorities)) {
            List<AuthorityDTO> dtoList = authorities.stream().map(this::toDTO)
                    .sorted(Comparator.comparing(AuthorityDTO::getSequence)).collect(Collectors.toList());
            res = getAuthorityChildTreeNodes(dtoList);
        }
        return res;
    }

    private List<AuthorityDTO> getAuthorityChildTreeNodes(List<AuthorityDTO> list) {
        List<AuthorityDTO> returnList = new ArrayList<>();
        // 获取一级节点建树
        List<AuthorityDTO> parents = list.stream().filter(d -> d.getParentId() == null).collect(Collectors.toList());
        for (AuthorityDTO departmentDTO : parents) {
            // 一级节点建树
            recursionFn(list, departmentDTO);
            returnList.add(departmentDTO);
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<AuthorityDTO> list, AuthorityDTO node) {
        List<AuthorityDTO> childList = getChildList(list, node);
        if (CollectionUtils.isEmpty(childList)) {
            return;
        }
        node.setRoutes(childList);
        for (AuthorityDTO tChild : childList) {
            recursionFn(list, tChild);
        }
    }

    /**
     * 得到子节点列表
     */
    private List<AuthorityDTO> getChildList(List<AuthorityDTO> list, AuthorityDTO t) {
        List<AuthorityDTO> tList = new ArrayList<>();

        for (AuthorityDTO treeNode : list) {
            if (null == treeNode.getParentId()) {
                continue;
            }
            if (Objects.equals(treeNode.getParentId(), t.getId())) {
                tList.add(treeNode);
            }
        }
        return tList;
    }
}
